﻿#region

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using xConnected.Core.Common.Paging;
using xConnected.Core.Interfaces.Data;
using xConnected.Core.Interfaces.Paging;
using xConnected.Core.Model;
using xConnected.Core.Model.ViewModel;

#endregion

namespace xConnected.Data
{
    public partial class ExpertProfileRepository : BaseRepository<ExpertProfile>, IExpertProfileRepository
    {
        #region IExpertProfileRepository Members

        public int GetExpertProfilesCount()
        {
            return DbSet.Count();
        }

        public List<ExpertProfile> GetExpertProfiles(int startIndex, int count)
        {
            IEnumerable<ExpertProfile> query = DbSet;
            return count > 0
                       ? query.Skip(startIndex).Take(count).ToList() //Paging
                       : query.ToList(); //No paging
        }


        public override ExpertProfile GetById(int id)
        {
            return DbSet
                .Include(p => p.User)
                .Include(p => p.User.ExpertProfiles)
                .Include(p => p.User.CompanyProfiles)
                .Include(p => p.User.CompanyProfiles.Select(c => c.Positions))
                .Include(p => p.CategorySkills)
                .Include(p => p.EducationSkills)
                .Include(p => p.Country)
                .Include(p => p.LanguageSkills)
                .Include(p => p.TechnologySkills).SingleOrDefault(p => p.Id == id);
        }

        public override IQueryable<ExpertProfile> GetAll()
        {
            return DbSet
                .Include(p => p.User)
                .Include(p => p.Country)
                .Include(p => p.Industry)
                .Include(p => p.CategorySkills)
                .Include(p => p.EducationSkills)
                .Include(p => p.LanguageSkills)
                .Include(p => p.TechnologySkills);
        }

        public override IQueryable<ExpertProfile> GetAllReadOnly()
        {
            return DbSet
                .Include(p => p.User)
                .Include(p => p.CategorySkills)
                .Include(p => p.EducationSkills)
                .Include(p => p.Country)
                .Include(p => p.LanguageSkills)
                .Include(p => p.TechnologySkills)
                .AsNoTracking();
        }

        public IPage<ExpertProfile> AdvancedPagedSearchedAll(AdvancedSearchModelProfile expertModel)
        {
            var data = AdvancedSearchAll(expertModel);
            //if method is called from MyProfiles mode and if ShowAll is selected return all profiles
            //if ShowAll is not selected return only first 3 profiles
            expertModel.PageSize = expertModel.UserId != 0
                                       ? expertModel.ShowAll ? data.Count() : 3
                                       : expertModel.PageSize;
            var pagedData =
                data.OrderBy(k => k.Id).Skip(expertModel.PageSize*expertModel.PageIndex).Take(expertModel.PageSize).AsEnumerable();
            return new Page<ExpertProfile>(pagedData, data.Count(), expertModel.PageSize, expertModel.PageIndex);
        }

        public IPage<ExpertProfile> AdvancedPagedSearchedSome(AdvancedSearchModelProfile expertModel)
        {
            var data = AdvancedSearchSome(expertModel);
            var pagedData =
                data.OrderBy(k => k.Id).Skip(expertModel.PageSize*expertModel.PageIndex).Take(expertModel.PageSize)
                    .AsEnumerable();
            return new Page<ExpertProfile>(pagedData, data.Count(), expertModel.PageSize, expertModel.PageIndex);
        }


        public override void Delete(ExpertProfile entity)
        {
            DbSet.Remove(DbSet.Single(p => p.Id == entity.Id));
        }

        #endregion

        private IQueryable<ExpertProfile> AdvancedSearchAll(AdvancedSearchModelProfile profileModel)
        {
            IQueryable<ExpertProfile> profiles = profileModel.UserId == 0
                                                       ? DbSet
                                                       : DbSet.Where(p => p.User.Id == profileModel.UserId);

            if (profileModel.Keywords != null && profileModel.Keywords.Count != 0)
            {
                //if (profileModel.SimpleSearch)
                //{
                //    foreach (var keyword in profileModel.Keywords)
                //    {
                //        profiles =
                //            profiles.Where(p =>
                //                           p.Description.ToLower().Contains(keyword.ToLower()) ||
                //                           p.Experience.ToLower().Contains(keyword.ToLower()) ||
                //                           p.References.ToLower().Contains(keyword.ToLower()) ||
                //                           p.Other.ToLower().Contains(keyword.ToLower()) ||
                //                           p.CategorySkills.Any(
                //                               c => c.Category.Description.ToLower().Contains(keyword.ToLower())) ||
                //                           p.Country.Description.ToLower().Contains(keyword.ToLower()) ||
                //                           p.Country.ShortName.ToLower().Contains(keyword.ToLower()) ||
                //                           p.Industry.Description.ToLower().Contains(keyword.ToLower()) ||
                //                           p.EducationSkills.Any(
                //                               e => e.Education.Description.ToLower().Contains(keyword.ToLower())) ||
                //                           p.EducationSkills.Any(
                //                               e => e.Education.Title.ToLower().Contains(keyword.ToLower())) ||
                //                           p.TechnologySkills.Any(
                //                               t => t.Technology.Name.ToLower().Contains(keyword.ToLower())) ||
                //                           p.LanguageSkills.Any(
                //                               l => l.Language.Description.ToLower().Contains(keyword.ToLower())));
                //    }
                //}
                //else
                //{
                //    foreach (var keyword in profileModel.Keywords)
                //    {
                profiles =
                    profiles.Where(
                        p => profileModel.Keywords.Any(k => k.ToLower().Contains(p.Description.ToLower())) ||
                             profileModel.Keywords.Any(k => k.ToLower().Contains(p.Experience.ToLower())) ||
                             profileModel.Keywords.Any(k => k.ToLower().Contains(p.References.ToLower())) ||
                             profileModel.Keywords.Any(k => k.ToLower().Contains(p.Other.ToLower())));
                //    }
                //}
            }

            if (!String.IsNullOrEmpty(profileModel.Title))
            {
                if (profileModel.Title.Contains(" "))
                {
                    string[] TitleSplit = profileModel.Title.Split(' ');
                    profiles = profiles.Where(p => TitleSplit.Any(t => t.ToLower().Contains(p.Title.ToLower())) || p.Title.ToLower().Contains(profileModel.Title.ToLower()));
                }
                else
                {
                    profiles = profiles.Where(p => p.Title.ToLower().Contains(profileModel.Title.ToLower()));
                }
            }
            if (!String.IsNullOrEmpty(profileModel.Location))
            {
                foreach (var profile in profiles)
                {
                    if (
                        Math.Sqrt(Math.Pow((profileModel.XLocation.Value - profile.XLocation), 2) +
                                  Math.Pow((profileModel.YLocation.Value - profile.YLocation), 2)) <=
                        profileModel.Distance.Value)
                    {
                        profiles = profiles.Where(p => p.Id == profile.Id);
                    }
                }
            }
            if (profileModel.AvailabilityStatus.HasValue)
            {
                profiles = profiles.Where(p => p.AvailabilityStatus == profileModel.AvailabilityStatus.Value);
            }
            if (profileModel.JobType.HasValue)
            {
                profiles = profileModel.JobType != -1
                               ? profiles.Where(p => p.JobType == profileModel.JobType.Value)
                               : profiles;
            }

            if (profileModel.HourRateFrom.HasValue && profileModel.HourRateTo.HasValue)
            {
                profiles = profiles.Where(p => p.HourRate >= profileModel.HourRateFrom.Value);
            }
            if (profileModel.HourRateFrom.HasValue && profileModel.HourRateTo.HasValue)
            {
                profiles = profiles.Where(p => p.HourRate <= profileModel.HourRateTo.Value);
            }
            if (profileModel.HourRateFrom.HasValue && profileModel.HourRateTo.HasValue)
            {
                profiles =
                    profiles.Where(
                        p =>
                        p.HourRate >= profileModel.HourRateFrom.Value && p.HourRate <= profileModel.HourRateTo.Value);
            }

            if (profileModel.DailyRateFrom.HasValue && profileModel.DailyRateTo.HasValue)
            {
                profiles = profiles.Where(p => p.DailyRate >= profileModel.DailyRateFrom.Value);
            }
            if (profileModel.DailyRateFrom.HasValue && profileModel.DailyRateTo.HasValue)
            {
                profiles = profiles.Where(p => p.DailyRate <= profileModel.DailyRateTo.Value);
            }
            if (profileModel.DailyRateFrom.HasValue && profileModel.DailyRateTo.HasValue)
            {
                profiles =
                    profiles.Where(
                        p =>
                        p.DailyRate >= profileModel.DailyRateFrom.Value && p.HourRate <= profileModel.DailyRateTo.Value);
            }

            if (profileModel.MonthlyRateFrom.HasValue && profileModel.MonthlyRateTo.HasValue)
            {
                profiles = profiles.Where(p => p.MonthlyRate >= profileModel.MonthlyRateFrom.Value);
            }
            if (profileModel.MonthlyRateFrom.HasValue && profileModel.MonthlyRateTo.HasValue)
            {
                profiles = profiles.Where(p => p.MonthlyRate <= profileModel.MonthlyRateTo.Value);
            }
            if (profileModel.MonthlyRateFrom.HasValue && profileModel.MonthlyRateTo.HasValue)
            {
                profiles =
                    profiles.Where(
                        p =>
                        p.MonthlyRate >= profileModel.MonthlyRateFrom.Value &&
                        p.MonthlyRate <= profileModel.MonthlyRateTo.Value);
            }

            if (profileModel.AnnualRateFrom.HasValue && profileModel.AnnualRateTo.HasValue)
            {
                profiles = profiles.Where(p => p.AnnualRate >= profileModel.AnnualRateFrom.Value);
            }
            if (profileModel.AnnualRateFrom.HasValue && profileModel.AnnualRateTo.HasValue)
            {
                profiles = profiles.Where(p => p.AnnualRate <= profileModel.AnnualRateTo.Value);
            }
            if (profileModel.AnnualRateFrom.HasValue && profileModel.AnnualRateTo.HasValue)
            {
                profiles =
                    profiles.Where(
                        p =>
                        p.AnnualRate >= profileModel.AnnualRateFrom.Value &&
                        p.AnnualRate <= profileModel.AnnualRateTo.Value);
            }
            if (profileModel.CountryIds != null && profileModel.CountryIds.Count != 0)
            {
                profiles = profileModel.CountryIds[0] != -1
                               ? profiles.Where(p => profileModel.CountryIds.Contains(p.CountryId))
                               : profiles;
            }
            if (profileModel.IndustryIds != null && profileModel.IndustryIds.Count != 0)
            {
                profiles = profileModel.IndustryIds[0] != -1
                               ? profiles.Where(p => profileModel.IndustryIds.Contains(p.Industry.Id))
                               : profiles;
            }
            if (profileModel.CategoryIds != null && profileModel.CategoryIds.Count != 0)
            {
                profiles =
                    profiles.Where(
                        p => p.CategorySkills.Select(c => c.CategoryId).Any(id => profileModel.CategoryIds.Contains(id)));
            }
            if (profileModel.TechnologyIds != null && profileModel.TechnologyIds.Count != 0)
            {
                profiles =
                    profiles.Where(
                        p =>
                        p.TechnologySkills.Select(c => c.TechnologyId).Any(id => profileModel.TechnologyIds.Contains(id)));
            }
            if (profileModel.LanguageIds != null && profileModel.LanguageIds.Count != 0)
            {
                profiles =
                    profiles.Where(
                        p => p.LanguageSkills.Select(c => c.LanguageId).Any(id => profileModel.LanguageIds.Contains(id)));
            }
            if (profileModel.EducationIds != null && profileModel.EducationIds.Count != 0)
            {
                profiles =
                    profiles.Where(
                        p =>
                        p.EducationSkills.Select(c => c.EducationId).Any(id => profileModel.EducationIds.Contains(id)));
            }

             return profiles.Include(p => p.User)
                            .Include(p => p.Country)
                            .Include(p => p.Industry)
                            .Include(p => p.CategorySkills.Select(x => x.Category.TitleTranslations.Select(t => t.Language)))
                            .Include(p => p.CategorySkills.Select(x => x.Category.DescriptionTranslations.Select(t => t.Language)))
                            .Include(p => p.TechnologySkills.Select(x => x.Technology))
                            .Include(p => p.EducationSkills.Select(x => x.Education))
                            .Include(p => p.LanguageSkills.Select(x => x.Language))
                            .AsNoTracking();
        }

        private IQueryable<ExpertProfile> AdvancedSearchSome(AdvancedSearchModelProfile profileModel)
        {
            IQueryable<ExpertProfile> profiles = GetAll();
            var profilesList = profiles.Where(p => p.Id == -1);

            IQueryable<ExpertProfile> profilesName;
            IQueryable<ExpertProfile> profilesLocation;
            IQueryable<ExpertProfile> profilesAvailability;
            IQueryable<ExpertProfile> profilesHourRate;
            IQueryable<ExpertProfile> profilesDailyRate;
            IQueryable<ExpertProfile> profilesMonthlyRate;
            IQueryable<ExpertProfile> profilesAnnualRate;
            IQueryable<ExpertProfile> profilesEmployment;
            IQueryable<ExpertProfile> profilesCountries;
            IQueryable<ExpertProfile> profilesIndustries;
            IQueryable<ExpertProfile> profilesCategories;
            IQueryable<ExpertProfile> profilesTechnologies;
            IQueryable<ExpertProfile> profilesLanguages;
            IQueryable<ExpertProfile> profilesEducations;
            IQueryable<ExpertProfile> profilesKeywords = profiles.Where(p => p.Id == -1);

            if (profileModel.Keywords != null)
            {
                //if (profileModel.SimpleSearch)
                //{
                //    foreach (var keyword in profileModel.Keywords)
                //    {
                //        profilesKeywords =
                //            profiles.Where(p =>
                //                           p.Description.ToLower().Contains(keyword.ToLower()) ||
                //                           p.Experience.ToLower().Contains(keyword.ToLower()) ||
                //                           p.References.ToLower().Contains(keyword.ToLower()) ||
                //                           p.Other.ToLower().Contains(keyword.ToLower()) ||
                //                           p.CategorySkills.Any(
                //                               c =>
                //                               c.Category.Description.ToLower().Contains(keyword.ToLower())) ||
                //                           p.Country.Description.ToLower().Contains(keyword.ToLower()) ||
                //                           p.Country.ShortName.ToLower().Contains(keyword.ToLower()) ||
                //                           p.EducationSkills.Any(
                //                               e =>
                //                               e.Education.Description.ToLower().Contains(
                //                                   keyword.ToLower())) ||
                //                           p.EducationSkills.Any(
                //                               e =>
                //                               e.Education.Title.ToLower().Contains(keyword.ToLower())) ||
                //                           p.TechnologySkills.Any(
                //                               t =>
                //                               t.Technology.Name.ToLower().Contains(keyword.ToLower())) ||
                //                           p.LanguageSkills.Any(
                //                               l =>
                //                               l.Language.Description.ToLower().Contains(keyword.ToLower())));
                //    }
                //}
                //else
                //{
                //    foreach (var keyword in profileModel.Keywords)
                //    {
                profilesKeywords =
                    profiles.Where(
                        p => profileModel.Keywords.Any(k => k.ToLower().Contains(p.Description.ToLower())) ||
                             profileModel.Keywords.Any(k => k.ToLower().Contains(p.Experience.ToLower())) ||
                             profileModel.Keywords.Any(k => k.ToLower().Contains(p.References.ToLower())) ||
                             profileModel.Keywords.Any(k => k.ToLower().Contains(p.Other.ToLower())));
                //    }
                //}
                profilesList = profilesList.Union(profilesKeywords);
            }
            if (profileModel.Title != null)
            {
                if (profileModel.Title.Contains(" "))
                {
                    string[] TitleSplit = profileModel.Title.Split(' ');
                    profilesName = profiles.Where(p => TitleSplit.Any(t => t.ToLower().Contains(p.Title.ToLower())) || p.Title.ToLower().Contains(profileModel.Title.ToLower()));
                }
                else
                {
                    profilesName = profiles.Where(p => p.Title.ToLower().Contains(profileModel.Title.ToLower()));
                }
                profilesList = profilesList.Union(profilesName);
            }
            if (profileModel.Location != null)
            {
                profilesLocation =
                    profiles.Where(
                        p =>
                        Math.Sqrt(Math.Pow((profileModel.XLocation.Value - p.XLocation), 2) +
                                  Math.Pow((profileModel.YLocation.Value - p.YLocation), 2)) <=
                        profileModel.Distance.Value);
                profilesList = profilesList.Union(profilesLocation);
            }
            if (profileModel.AvailabilityStatus.HasValue)
            {
                profilesAvailability =
                    profiles.Where(p => p.AvailabilityStatus == profileModel.AvailabilityStatus.Value);
                profilesList = profilesList.Union(profilesAvailability);
            }
            if (profileModel.JobType.HasValue)
            {
                if (profileModel.JobType != -1)
                {
                    profilesEmployment = profiles.Where(p => p.JobType == profileModel.JobType.Value);
                    profilesList = profilesList.Union(profilesEmployment);
                }
            }

            if (profileModel.HourRateFrom.HasValue && profileModel.HourRateTo.HasValue)
            {
                profilesHourRate = profiles.Where(p => p.HourRate >= profileModel.HourRateFrom.Value);
                profilesList = profilesList.Union(profilesHourRate);
            }
            if (profileModel.HourRateFrom.HasValue && profileModel.HourRateTo.HasValue)
            {
                profilesHourRate = profiles.Where(p => p.HourRate <= profileModel.HourRateTo.Value);
                profilesList = profilesList.Union(profilesHourRate);
            }
            if (profileModel.HourRateFrom.HasValue && profileModel.HourRateTo.HasValue)
            {
                profilesHourRate =
                    profiles.Where(
                        p =>
                        p.HourRate >= profileModel.HourRateFrom.Value && p.HourRate <= profileModel.HourRateTo.Value);
                profilesList = profilesList.Union(profilesHourRate);
            }

            if (profileModel.DailyRateFrom.HasValue && profileModel.DailyRateTo.HasValue)
            {
                profilesDailyRate = profiles.Where(p => p.DailyRate >= profileModel.DailyRateFrom.Value);
                profilesList = profilesList.Union(profilesDailyRate);
            }
            if (profileModel.DailyRateFrom.HasValue && profileModel.DailyRateTo.HasValue)
            {
                profilesDailyRate = profiles.Where(p => p.DailyRate <= profileModel.DailyRateTo.Value);
                profilesList = profilesList.Union(profilesDailyRate);
            }
            if (profileModel.DailyRateFrom.HasValue && profileModel.DailyRateTo.HasValue)
            {
                profilesDailyRate =
                    profiles.Where(
                        p =>
                        p.DailyRate >= profileModel.DailyRateFrom.Value && p.HourRate <= profileModel.DailyRateTo.Value);
                profilesList = profilesList.Union(profilesDailyRate);
            }

            if (profileModel.MonthlyRateFrom.HasValue && profileModel.MonthlyRateTo.HasValue)
            {
                profilesMonthlyRate = profiles.Where(p => p.MonthlyRate >= profileModel.MonthlyRateFrom.Value);
                profilesList = profilesList.Union(profilesMonthlyRate);
            }
            if (profileModel.MonthlyRateFrom.HasValue && profileModel.MonthlyRateTo.HasValue)
            {
                profilesMonthlyRate = profiles.Where(p => p.MonthlyRate <= profileModel.MonthlyRateTo.Value);
                profilesList = profilesList.Union(profilesMonthlyRate);
            }
            if (profileModel.MonthlyRateFrom.HasValue && profileModel.MonthlyRateTo.HasValue)
            {
                profilesMonthlyRate =
                    profiles.Where(
                        p =>
                        p.MonthlyRate >= profileModel.MonthlyRateFrom.Value &&
                        p.MonthlyRate <= profileModel.MonthlyRateTo.Value);
                profilesList = profilesList.Union(profilesMonthlyRate);
            }

            if (profileModel.AnnualRateFrom.HasValue && profileModel.AnnualRateTo.HasValue)
            {
                profilesAnnualRate = profiles.Where(p => p.AnnualRate >= profileModel.AnnualRateFrom.Value);
                profilesList = profilesList.Union(profilesAnnualRate);
            }
            if (profileModel.AnnualRateFrom.HasValue && profileModel.AnnualRateTo.HasValue)
            {
                profilesAnnualRate = profiles.Where(p => p.AnnualRate <= profileModel.AnnualRateTo.Value);
                profilesList = profilesList.Union(profilesAnnualRate);
            }
            if (profileModel.AnnualRateFrom.HasValue && profileModel.AnnualRateTo.HasValue)
            {
                profilesAnnualRate =
                    profiles.Where(
                        p =>
                        p.AnnualRate >= profileModel.AnnualRateFrom.Value &&
                        p.AnnualRate <= profileModel.AnnualRateTo.Value);
                profilesList = profilesList.Union(profilesAnnualRate);
            }
            if (profileModel.CountryIds != null)
            {
                if (profileModel.CountryIds[0] != -1)
                {
                    profilesCountries =
                        profiles.Where(p => profileModel.CountryIds.Contains(p.CountryId));
                    profilesList = profilesList.Union(profilesCountries);
                }
            }
            if (profileModel.IndustryIds != null)
            {
                if (profileModel.IndustryIds[0] != -1)
                {
                    profilesIndustries = profiles.Where(p => profileModel.IndustryIds.Contains(p.Industry.Id));
                    profilesList = profilesList.Union(profilesIndustries);
                }
            }
            if (profileModel.CategoryIds != null)
            {
                profilesCategories =
                    profiles.Where(
                        p => p.CategorySkills.Select(c => c.CategoryId).Any(id => profileModel.CategoryIds.Contains(id)));
                profilesList = profilesList.Union(profilesCategories);
            }
            if (profileModel.TechnologyIds != null)
            {
                profilesTechnologies =
                    profiles.Where(
                        p =>
                        p.TechnologySkills.Select(c => c.TechnologyId).Any(id => profileModel.TechnologyIds.Contains(id)));
                profilesList = profilesList.Union(profilesTechnologies);
            }
            if (profileModel.LanguageIds != null)
            {
                profilesLanguages =
                    profiles.Where(
                        p => p.LanguageSkills.Select(c => c.LanguageId).Any(id => profileModel.LanguageIds.Contains(id)));
                profilesList = profilesList.Union(profilesLanguages);
            }
            if (profileModel.EducationIds != null)
            {
                profilesEducations =
                    profiles.Where(
                        p =>
                        p.EducationSkills.Select(c => c.EducationId).Any(id => profileModel.EducationIds.Contains(id)));
                profilesList = profilesList.Union(profilesEducations);
            }

            return profilesList;
        }
    }
}